package com.base.self.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.base.mapper.voipmapper.SubscribersMapper;
import com.base.mapper.voipmapper.UsersMapper;
import com.base.pay.ali.AliPayRequest;
import com.base.pay.ali.service.AliPayEasyService;
import com.base.pay.wx.WxPayRequest;
import com.base.pay.wx.service.WxPayEasyService;
import com.base.po.voip.Subscribers;
import com.base.po.voip.Users;
import com.base.result.PageUtils;
import com.base.result.ResponseResult;
import com.base.result.ResponseResultUtils;
import com.base.self.common.SelfRuntimeException;
import com.base.self.dto.selfApplyRefund.SelfApplyRefundWebListDTO;
import com.base.self.dto.selfApplyRefund.SelfApplyRefundWebNoDTO;
import com.base.self.dto.selfApplyRefund.SelfApplyRefundWebOkDTO;
import com.base.self.entity.Ptintegral;
import com.base.self.entity.SelfApplyRefund;
import com.base.self.entity.SelfOrder;
import com.base.self.mapper.PtintegralMapper;
import com.base.self.mapper.SelfApplyRefundMapper;
import com.base.self.mapper.SelfOrderMapper;
import com.base.self.service.ISelfApplyRefundService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.base.self.vos.VosRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;

/**
 * 退款申请
 *
 * @author XiFYuW
 * @since 2020-12-20
 */
@Service
public class SelfApplyRefundServiceImpl extends ServiceImpl<SelfApplyRefundMapper, SelfApplyRefund> implements ISelfApplyRefundService {

    private final SelfApplyRefundMapper selfApplyRefundMapper;

    private final SelfOrderMapper selfOrderMapper;

    private final WxPayEasyService wxPayEasyService;

    private final AliPayEasyService aliPayEasyService;

    private final PtintegralMapper ptintegralMapper;

    private final VosRequest vosRequest;

    private final UsersMapper usersMapper;

    private final SubscribersMapper subscribersMapper;

    public SelfApplyRefundServiceImpl(SelfApplyRefundMapper selfApplyRefundMapper,
                                      SelfOrderMapper selfOrderMapper,
                                      WxPayEasyService wxPayEasyService,
                                      AliPayEasyService aliPayEasyService,
                                      PtintegralMapper ptintegralMapper,
                                      VosRequest vosRequest,
                                      UsersMapper usersMapper,
                                      SubscribersMapper subscribersMapper) {
        this.selfApplyRefundMapper = selfApplyRefundMapper;
        this.selfOrderMapper = selfOrderMapper;
        this.wxPayEasyService = wxPayEasyService;
        this.aliPayEasyService = aliPayEasyService;
        this.ptintegralMapper = ptintegralMapper;
        this.vosRequest = vosRequest;
        this.usersMapper = usersMapper;
        this.subscribersMapper = subscribersMapper;
    }

    @Override
    @Transactional(readOnly = true)
    public ResponseResult selfApplyRefundWebList(SelfApplyRefundWebListDTO selfApplyRefundWebListDTO) {
        String applyMobile = selfApplyRefundWebListDTO.getApplyMobile();
        Integer status = selfApplyRefundWebListDTO.getStatus();
        final Map<String, Object> data = PageUtils.getDateMap(() -> page(PageUtils.getPage(
                new Page<>(), selfApplyRefundWebListDTO.getOffset(), selfApplyRefundWebListDTO.getLimit()),
                new LambdaQueryWrapper<SelfApplyRefund>()
                        .eq(!StringUtils.isEmpty(applyMobile), SelfApplyRefund::getApplyMobile, applyMobile)
                        .eq(status != null && status != 0, SelfApplyRefund::getStatus, status)
                        .eq(SelfApplyRefund::getIsDel, 0)
                        .orderByDesc(SelfApplyRefund::getCreateTime)));
        return ResponseResultUtils.getResponseResultS("查询成功", data);
    }

    @Override
    @Transactional
    public ResponseResult selfApplyRefundWebOk(SelfApplyRefundWebOkDTO selfApplyRefundWebOkDTO) {
        final SelfApplyRefund selfApplyRefund = selfApplyRefundMapper.selectOne(new LambdaQueryWrapper<SelfApplyRefund>()
                .eq(SelfApplyRefund::getId, selfApplyRefundWebOkDTO.getId())
                .eq(SelfApplyRefund::getIsDel, 0)
        );
        Optional.ofNullable(selfApplyRefund).orElseThrow(() -> new SelfRuntimeException(ResponseResultUtils.getResponseResultF("审核记录不存在")));

        if (selfApplyRefund.getStatus() != 1) {
            throw new SelfRuntimeException(ResponseResultUtils.getResponseResultF("该记录已处理，请勿重复处理。"));
        }

        final SelfOrder selfOrder = selfOrderMapper.selectOne(new LambdaQueryWrapper<SelfOrder>()
                .eq(SelfOrder::getOrderNo, selfApplyRefund.getOrderNo())
        );
        Optional.ofNullable(selfOrder).orElseThrow(() -> new SelfRuntimeException(ResponseResultUtils.getResponseResultF("订单信息不存在")));

        if (selfOrder.getStatus() != 3 && selfOrder.getStatus() != 4 && selfOrder.getStatus() != 2) {
            throw new SelfRuntimeException(ResponseResultUtils.getResponseResultF("订单状态错误"));
        }
        if (selfOrder.getPayWay() == 1) {
            final AliPayRequest aliPayRequest = AliPayRequest.builder()
                    .outTradeNo(selfOrder.getOrderNo())
                    .refundAmount(AliPayRequest.ALI_DF.format(selfOrder.getRealPrice()))
                    .RequestNo(IdUtil.fastSimpleUUID())
                    .parentId(selfOrder.getParentId())
                    .build();
            aliPayEasyService.refund(aliPayRequest, (map) -> {
                refundVos(selfOrder);

                selfApplyRefund.setUpdateTime(DateUtil.date());
                selfApplyRefund.setStatus(2);
                selfApplyRefund.setRemark(selfApplyRefundWebOkDTO.getRemark());
                selfApplyRefund.setRefundTime(DateUtil.date());
                selfApplyRefund.setRefundDeal(String.valueOf(map.get("trade_no")));
                selfApplyRefund.setRefundMoney(selfOrder.getRealPrice());
                selfApplyRefund.setRefundWay(selfOrder.getPayWay());
                selfApplyRefund.setRefundIntegral(selfOrder.getDiscountPrice());
                selfApplyRefund.setIsPerform(1);
                selfApplyRefundMapper.updateById(selfApplyRefund);

                refundPt(selfOrder);
            });
        }
        if (selfOrder.getPayWay() == 2) {
            Map<String, String> params = new TreeMap<>();
            params.put("out_trade_no", selfOrder.getOrderNo());
            params.put("out_refund_no", IdUtil.fastSimpleUUID());
            params.put("total_fee", WxPayRequest.WX_DF.format(selfOrder.getRealPrice().multiply(new BigDecimal(100))));
            params.put("refund_fee", WxPayRequest.WX_DF.format(selfOrder.getRealPrice().multiply(new BigDecimal(100))));
            params.put("refund_desc", selfApplyRefund.getReason());
            final WxPayRequest wxPayRequest = WxPayRequest.builder()
                    .params(params)
                    .parentId(selfOrder.getParentId())
                    .build();
            wxPayEasyService.refund(wxPayRequest, (data) -> {
                refundVos(selfOrder);

                selfApplyRefund.setUpdateTime(DateUtil.date());
                selfApplyRefund.setStatus(2);
                selfApplyRefund.setRemark(selfApplyRefundWebOkDTO.getRemark());
                selfApplyRefund.setRefundTime(DateUtil.date());
                selfApplyRefund.setRefundDeal(String.valueOf(data.get("transaction_id")));
                selfApplyRefund.setRefundMoney(selfOrder.getRealPrice());
                selfApplyRefund.setRefundWay(selfOrder.getPayWay());
                selfApplyRefund.setRefundIntegral(selfOrder.getDiscountPrice());
                selfApplyRefund.setIsPerform(1);
                selfApplyRefundMapper.updateById(selfApplyRefund);

                refundPt(selfOrder);
            });
        }
        if (selfOrder.getPayWay() == 4) {
            selfApplyRefund.setUpdateTime(DateUtil.date());
            selfApplyRefund.setStatus(2);
            selfApplyRefund.setRemark(selfApplyRefundWebOkDTO.getRemark());
            selfApplyRefund.setRefundTime(DateUtil.date());
            selfApplyRefund.setRefundDeal("");
            selfApplyRefund.setRefundMoney(selfOrder.getRealPrice());
            selfApplyRefund.setRefundWay(selfOrder.getPayWay());
            selfApplyRefund.setRefundIntegral(selfOrder.getDiscountPrice());
            selfApplyRefund.setIsPerform(1);
            selfApplyRefundMapper.updateById(selfApplyRefund);
            refundPt(selfOrder);
        }

        updateSelfOrderStatus(selfOrder, 2);
        return ResponseResultUtils.getResponseResultS("退款成功");
    }

    @Override
    @Transactional
    public ResponseResult selfApplyRefundWebNo(SelfApplyRefundWebNoDTO selfApplyRefundWebNoDTO) {
        final SelfApplyRefund selfApplyRefund = selfApplyRefundMapper.selectOne(new LambdaQueryWrapper<SelfApplyRefund>()
                .eq(SelfApplyRefund::getId, selfApplyRefundWebNoDTO.getId())
                .eq(SelfApplyRefund::getIsDel, 0)
        );
        Optional.ofNullable(selfApplyRefund).orElseThrow(() -> new SelfRuntimeException(ResponseResultUtils.getResponseResultF("审核记录不存在")));
        final SelfOrder selfOrder = selfOrderMapper.selectOne(new LambdaQueryWrapper<SelfOrder>()
                .eq(SelfOrder::getOrderNo, selfApplyRefund.getOrderNo())
        );
        Optional.ofNullable(selfOrder).orElseThrow(() -> new SelfRuntimeException(ResponseResultUtils.getResponseResultF("订单信息不存在")));
        selfApplyRefund.setUpdateTime(DateUtil.date());
        selfApplyRefund.setStatus(3);
        selfApplyRefund.setRemark(selfApplyRefundWebNoDTO.getRemark());
        selfApplyRefund.setNoReason(selfApplyRefundWebNoDTO.getNoReason());
        selfApplyRefund.setRefundTime(DateUtil.date());
        selfApplyRefund.setRefundDeal("");
        selfApplyRefund.setRefundMoney(BigDecimal.ZERO);
        selfApplyRefund.setRefundWay(0);
        selfApplyRefund.setRefundIntegral(BigDecimal.ZERO);
        selfApplyRefund.setIsPerform(1);
        selfApplyRefundMapper.updateById(selfApplyRefund);

        updateSelfOrderStatus(selfOrder, 3);
        return ResponseResultUtils.getResponseResultS("拒绝成功");
    }

    private void refundPt(final SelfOrder selfOrder){
        /*退积分*/
        if (selfOrder.getDiscountPrice().compareTo(BigDecimal.ZERO) > 0) {
            final Ptintegral ptintegral = new Ptintegral();
            ptintegral.setStatus(1);
            ptintegral.setType(1);
            ptintegral.setSub(selfOrder.getUserId());
            ptintegral.setMoney(selfOrder.getDiscountPrice());
            ptintegral.setContext("退款[" + selfOrder.getOrderNo() + "]所返");
            ptintegral.setCreateTime(DateUtil.date());
            ptintegralMapper.insert(ptintegral);
        }
    }

    private void refundVos(final SelfOrder selfOrder){
        final Users users = usersMapper.selectByPrimaryKey(selfOrder.getParentId());
        final Subscribers subscribers = subscribersMapper.selectByPrimaryKey(selfOrder.getUserId());
        vosRequest.refundVos(users, subscribers, selfOrder.getOrderNo(), selfOrder.getRealPrice().negate());
    }

    private void updateSelfOrderStatus(final SelfOrder selfOrder, final Integer refundStatus){
        /*修改话费订单状态*/
        final SelfOrder selfOrderCarrier = selfOrderMapper.selectOne(new LambdaQueryWrapper<SelfOrder>()
                .eq(SelfOrder::getCarrierId, selfOrder.getId())
                .eq(SelfOrder::getIsDel, 0)
        );
        Optional.ofNullable(selfOrderCarrier).ifPresent(x -> {
            x.setRefundStatus(2);
            x.setUpdateTime(DateUtil.date());
            selfOrderMapper.updateById(x);
        });

        selfOrder.setRefundStatus(refundStatus);
        selfOrder.setUpdateTime(DateUtil.date());
        selfOrderMapper.updateById(selfOrder);
    }
}
